package arithmetic.socket.nio;


import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

/**
 * nio学习selector  一个线程监听多个io
 *
 * 目前此程序有个bug , 连接多个客户端时,其中一个断了,就会造成死循环
 *
 * @author jiangfeng
 * Created on 2020-03-26
 */
public class NioTest5 {
    public static void main(String[] args) throws Exception {

        // 打开一个选择器
        Selector selector = Selector.open();

        // 会根据不同的操作系统返回不同的selector实现类, mac返回:sun.nio.ch.KQueueSelectorImpl
        System.out.println(selector.getClass());

        for (int i = 0; i < 10; i++) {
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            // 设置为非阻塞方式
            serverSocketChannel.configureBlocking(false);
            // 绑定监听端口
            serverSocketChannel.socket().bind(new InetSocketAddress(8899 + i));

            System.out.println("监听端口： " + (8899 + i));
            // 注册到selector上
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        }


        while (true) {
            // 不断循环选择器 执行选择 (没有选到事件就会阻塞住)
             int numbers = selector.select();
             System.out.println("numbers: " + numbers);

            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            System.out.println("selectionKeys:" + selectionKeys);
            Iterator<SelectionKey> iterator = selectionKeys.iterator();

            // 事件模型
            while (iterator.hasNext()) {
                SelectionKey selectionKey = iterator.next();
                // 建立了可接受连接
                if (selectionKey.isAcceptable()) {
                    ServerSocketChannel serverChannel = (ServerSocketChannel) selectionKey.channel();
                    SocketChannel socketChannel = serverChannel.accept();
                    // 设置socket连接为非阻塞
                    socketChannel.configureBlocking(false);
                    // 有连接接注册到selector上
                    socketChannel.register(selector, SelectionKey.OP_READ);
                    iterator.remove();
                    System.out.println("连接:" + socketChannel.getRemoteAddress());
                } else if (selectionKey.isReadable()) {
                    // 读取socket通讯信息
                    SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
                    int read = 0;
                    while (true) {
                        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                        byteBuffer.clear();
                        read = socketChannel.read(byteBuffer);
                        if (read <= 0) {
                            break;
                        }

                        byteBuffer.flip();
                        // 原样返回给客户端
                        socketChannel.write(byteBuffer);
                    }
                    System.out.println("读取客户端:" + read + " [来自]:" + socketChannel);

                    // 处理完毕可读事件 移去
                    iterator.remove();
                }
            }
        }


    }
}
